home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Mac / Lib / FrameWork.py < prev    next >
Text File  |  1996-04-23  |  22KB  |  832 lines

  1. "A sort of application framework for the Mac"
  2.  
  3. DEBUG=0
  4.  
  5. import MacOS
  6. import traceback
  7.  
  8. from AE import *
  9. from AppleEvents import *
  10. from Ctl import *
  11. from Controls import *
  12. from Dlg import *
  13. from Dialogs import *
  14. from Evt import *
  15. from Events import *
  16. from Menu import *
  17. from Menus import *
  18. from Qd import *
  19. from QuickDraw import *
  20. #from Res import *
  21. #from Resources import *
  22. #from Snd import *
  23. #from Sound import *
  24. from Win import *
  25. from Windows import *
  26.  
  27. import EasyDialogs
  28.  
  29. kHighLevelEvent = 23    # Don't know what header file this should come from
  30. SCROLLBARWIDTH = 16        # Again, not a clue...
  31.  
  32.  
  33. # Map event 'what' field to strings
  34. eventname = {}
  35. eventname[1] = 'mouseDown'
  36. eventname[2] = 'mouseUp'
  37. eventname[3] = 'keyDown'
  38. eventname[4] = 'keyUp'
  39. eventname[5] = 'autoKey'
  40. eventname[6] = 'updateEvt'
  41. eventname[7] = 'diskEvt'
  42. eventname[8] = 'activateEvt'
  43. eventname[15] = 'osEvt'
  44. eventname[23] = 'kHighLevelEvent'
  45.  
  46. # Map part codes returned by WhichWindow() to strings
  47. partname = {}
  48. partname[0] = 'inDesk'
  49. partname[1] = 'inMenuBar'
  50. partname[2] = 'inSysWindow'
  51. partname[3] = 'inContent'
  52. partname[4] = 'inDrag'
  53. partname[5] = 'inGrow'
  54. partname[6] = 'inGoAway'
  55. partname[7] = 'inZoomIn'
  56. partname[8] = 'inZoomOut'
  57.  
  58. #
  59. # The useable portion of the screen
  60. #
  61. screenbounds = qd.screenBits.bounds
  62. screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
  63.     screenbounds[2]-4, screenbounds[3]-4
  64.     
  65. next_window_x = 40
  66. next_window_y = 40
  67.  
  68. def windowbounds(width, height):
  69.     "Return sensible window bounds"
  70.     global next_window_x, next_window_y
  71.     r, b = next_window_x+width, next_window_y+height
  72.     if r > screenbounds[2]:
  73.         next_window_x = 40
  74.     if b > screenbounds[3]:
  75.         next_window_y = 40
  76.     l, t = next_window_x, next_window_y
  77.     r, b = next_window_x+width, next_window_y+height
  78.     next_window_x, next_window_y = next_window_x+20, next_window_y+20
  79.     return l, t, r, b
  80.  
  81.  
  82. class Application:
  83.     
  84.     "Application framework -- your application should be a derived class"
  85.     
  86.     def __init__(self):
  87.         self._windows = {}
  88.         self.makemenubar()
  89.     
  90.     def makemenubar(self):
  91.         self.menubar = MenuBar()
  92.         AppleMenu(self.menubar, self.getabouttext(), self.do_about)
  93.         self.makeusermenus()
  94.  
  95.     def makeusermenus(self):
  96.         self.filemenu = m = Menu(self.menubar, "File")
  97.         self._quititem = MenuItem(m, "Quit", "Q", self._quit)
  98.     
  99.     def _quit(self, *args):
  100.         raise self
  101.         
  102.     def appendwindow(self, wid, window):
  103.         self._windows[wid] = window
  104.         
  105.     def removewindow(self, wid):
  106.         del self._windows[wid]
  107.     
  108.     def getabouttext(self):
  109.         return "About %s..." % self.__class__.__name__
  110.     
  111.     def do_about(self, id, item, window, event):
  112.         EasyDialogs.Message("Hello, world!" + "\015(%s)" % self.__class__.__name__)
  113.     
  114.     # The main event loop is broken up in several simple steps.
  115.     # This is done so you can override each individual part,
  116.     # if you have a need to do extra processing independent of the
  117.     # event type.
  118.     # Normally, however, you'd just define handlers for individual
  119.     # events.
  120.     # (XXX I'm not sure if using default parameter values is the right
  121.     # way to define the mask and wait time passed to WaitNextEvent.)
  122.     
  123.     def mainloop(self, mask = everyEvent, wait = 0):
  124.         saveyield = MacOS.EnableAppswitch(self.yield)
  125.         try:
  126.             while 1:
  127.                 try:
  128.                     self.do1event(mask, wait)
  129.                 except (Application, SystemExit):
  130.                     break
  131.         finally:
  132.             MacOS.EnableAppswitch(saveyield)
  133.     
  134.     yield = -1
  135.     
  136.     def do1event(self, mask = everyEvent, wait = 0):
  137.         ok, event = self.getevent(mask, wait)
  138.         if IsDialogEvent(event):
  139.             if self.do_dialogevent(event):
  140.                 return
  141.         if ok:
  142.             self.dispatch(event)
  143.         else:
  144.             self.idle(event)
  145.             
  146.     def idle(self, event):
  147.         pass
  148.     
  149.     def getevent(self, mask = everyEvent, wait = 0):
  150.         ok, event = WaitNextEvent(mask, wait)
  151.         return ok, event
  152.             
  153.     def dispatch(self, event):
  154.         (what, message, when, where, modifiers) = event
  155.         if eventname.has_key(what):
  156.             name = "do_" + eventname[what]
  157.         else:
  158.             name = "do_%d" % what
  159.         try:
  160.             handler = getattr(self, name)
  161.         except AttributeError:
  162.             handler = self.do_unknownevent
  163.         handler(event)
  164.         
  165.     def do_dialogevent(self, event):
  166.         gotone, window, item = DialogSelect(event)
  167.         if gotone:
  168.             if self._windows.has_key(window):
  169.                 self._windows[window].do_itemhit(item, event)
  170.             else:
  171.                 print 'Dialog event for unknown dialog'
  172.             return 1
  173.         return 0
  174.     
  175.     def do_mouseDown(self, event):
  176.         (what, message, when, where, modifiers) = event
  177.         partcode, wid = FindWindow(where)
  178.  
  179.         #
  180.         # Find the correct name.
  181.         #
  182.         if partname.has_key(partcode):
  183.             name = "do_" + partname[partcode]
  184.         else:
  185.             name = "do_%d" % partcode
  186.  
  187.         if wid == None:
  188.             # No window, or a non-python window    
  189.             try:
  190.                 handler = getattr(self, name)
  191.             except AttributeError:
  192.                 # Not menubar or something, so assume someone
  193.                 # else's window
  194.                 MacOS.HandleEvent(event)
  195.                 return        
  196.         elif self._windows.has_key(wid):
  197.             # It is a window. Hand off to correct window.
  198.             window = self._windows[wid]
  199.             try:
  200.                 handler = getattr(window, name)
  201.             except AttributeError:
  202.                 handler = self.do_unknownpartcode
  203.         else:
  204.             # It is a python-toolbox window, but not ours.
  205.             handler = self.do_unknownwindow
  206.         handler(partcode, wid, event)
  207.  
  208.     def do_inSysWindow(self, partcode, window, event):
  209.         MacOS.HandleEvent(event)
  210.     
  211.     def do_inDesk(self, partcode, window, event):
  212.         MacOS.HandleEvent(event)
  213.     
  214.     def do_inMenuBar(self, partcode, window, event):
  215.         (what, message, when, where, modifiers) = event
  216.         result = MenuSelect(where)
  217.         id = (result>>16) & 0xffff    # Hi word
  218.         item = result & 0xffff        # Lo word
  219.         self.do_rawmenu(id, item, window, event)
  220.     
  221.     def do_rawmenu(self, id, item, window, event):
  222.         try:
  223.             self.do_menu(id, item, window, event)
  224.         finally:
  225.             HiliteMenu(0)
  226.     
  227.     def do_menu(self, id, item, window, event):
  228.         self.menubar.dispatch(id, item, window, event)
  229.     
  230.     
  231.     def do_unknownpartcode(self, partcode, window, event):
  232.         (what, message, when, where, modifiers) = event
  233.         if DEBUG: print "Mouse down at global:", where
  234.         if DEBUG: print "\tUnknown part code:", partcode
  235.         if DEBUG: print "\tEvent:", self.printevent(event)
  236.         MacOS.HandleEvent(event)
  237.         
  238.     def do_unknownwindow(self, partcode, window, event):
  239.         if DEBUG: print 'Unknown window:', window
  240.         MacOS.HandleEvent(event)
  241.     
  242.     def do_keyDown(self, event):
  243.         self.do_key(event)
  244.     
  245.     def do_autoKey(self, event):
  246.         if not event[-1] & cmdKey:
  247.             self.do_key(event)
  248.     
  249.     def do_key(self, event):
  250.         (what, message, when, where, modifiers) = event
  251.         c = chr(message & charCodeMask)
  252.         if modifiers & cmdKey:
  253.             if c == '.':
  254.                 raise self
  255.             else:
  256.                 result = MenuKey(ord(c))
  257.                 id = (result>>16) & 0xffff    # Hi word
  258.                 item = result & 0xffff        # Lo word
  259.                 if id:
  260.                     self.do_rawmenu(id, item, None, event)
  261. #                elif c == 'w':
  262. #                    w = FrontWindow()
  263. #                    if w:
  264. #                        self.do_close(w)
  265. #                    else:
  266. #                        if DEBUG: print 'Command-W without front window'
  267.                 else:
  268.                     if DEBUG: print "Command-" +`c`
  269.         else:
  270.             # See whether the front window wants it
  271.             w = FrontWindow()
  272.             if w and self._windows.has_key(w):
  273.                 window = self._windows[w]
  274.                 try:
  275.                     do_char = window.do_char
  276.                 except AttributeError:
  277.                     do_char = self.do_char
  278.                 do_char(c, event)
  279.             # else it wasn't for us, sigh...
  280.     
  281.     def do_char(self, c, event):
  282.         if DEBUG: print "Character", `c`
  283.     
  284.     def do_updateEvt(self, event):
  285.         (what, message, when, where, modifiers) = event
  286.         wid = WhichWindow(message)
  287.         if wid and self._windows.has_key(wid):
  288.             window = self._windows[wid]
  289.             window.do_rawupdate(wid, event)
  290.         else:
  291.             MacOS.HandleEvent(event)
  292.     
  293.     def do_activateEvt(self, event):
  294.         (what, message, when, where, modifiers) = event
  295.         # XXXX Incorrect, should be fixed in suspendresume
  296.         if type(message) == type(1):
  297.             wid = WhichWindow(message)
  298.         else:
  299.             wid = message
  300.         if wid and self._windows.has_key(wid):
  301.             window = self._windows[wid]
  302.             window.do_activate(modifiers & 1, event)
  303.         else:
  304.             MacOS.HandleEvent(event)
  305.             
  306.     def do_osEvt(self, event):
  307.         (what, message, when, where, modifiers) = event
  308.         which = (message >> 24) & 0xff
  309.         if which == 1:    # suspend/resume
  310.             self.do_suspendresume(event)
  311.         else:
  312.             if DEBUG:
  313.                 print 'unknown osEvt:',
  314.                 self.printevent(event)
  315.                 
  316.     def do_suspendresume(self, event):
  317.         # Is this a good idea???
  318.         (what, message, when, where, modifiers) = event
  319.         w = FrontWindow()
  320.         if w:
  321.             # XXXX Incorrect, should stuff windowptr into message field
  322.             nev = (activateEvt, w, when, where, message&1)
  323.             self.do_activateEvt(nev)
  324.  
  325.     def do_kHighLevelEvent(self, event):
  326.         (what, message, when, where, modifiers) = event
  327.         if DEBUG: 
  328.             print "High Level Event:",
  329.             self.printevent(event)
  330.         try:
  331.             AEProcessAppleEvent(event)
  332.         except:
  333.             print "AEProcessAppleEvent error:"
  334.             traceback.print_exc()
  335.     
  336.     def do_unknownevent(self, event):
  337.         if DEBUG:
  338.             print "Unhandled event:",
  339.             self.printevent(event)
  340.     
  341.     def printevent(self, event):
  342.         (what, message, when, where, modifiers) = event
  343.         nicewhat = `what`
  344.         if eventname.has_key(what):
  345.             nicewhat = eventname[what]
  346.         print nicewhat,
  347.         if what == kHighLevelEvent:
  348.             h, v = where
  349.             print `ostypecode(message)`, hex(when), `ostypecode(h | (v<<16))`,
  350.         else:
  351.             print hex(message), hex(when), where,
  352.         print hex(modifiers)
  353.  
  354.  
  355. class MenuBar:
  356.     """Represent a set of menus in a menu bar.
  357.     
  358.     Interface:
  359.     
  360.     - (constructor)
  361.     - (destructor)
  362.     - addmenu
  363.     - addpopup (normally used internally)
  364.     - dispatch (called from Application)
  365.     """
  366.     
  367.     nextid = 1    # Necessarily a class variable
  368.     
  369.     def getnextid(self):
  370.         id = self.nextid
  371.         self.nextid = id+1
  372.         return id
  373.     
  374.     def __init__(self):
  375.         ClearMenuBar()
  376.         self.bar = GetMenuBar()
  377.         self.menus = {}
  378.     
  379.     def addmenu(self, title, after = 0):
  380.         id = self.getnextid()
  381.         if DEBUG: print 'Newmenu', title, id # XXXX
  382.         m = NewMenu(id, title)
  383.         m.InsertMenu(after)
  384.         DrawMenuBar()
  385.         return id, m
  386.         
  387.     def delmenu(self, id):
  388.         if DEBUG: print 'Delmenu', id # XXXX
  389.         DeleteMenu(id)
  390.     
  391.     def addpopup(self, title = ''):
  392.         return self.addmenu(title, -1)
  393.     
  394.     def install(self):
  395.         self.bar.SetMenuBar()
  396.         DrawMenuBar()
  397.     
  398.     def dispatch(self, id, item, window, event):
  399.         if self.menus.has_key(id):
  400.             self.menus[id].dispatch(id, item, window, event)
  401.         else:
  402.             if DEBUG: print "MenuBar.dispatch(%d, %d, %s, %s)" % \
  403.                 (id, item, window, event)
  404.     
  405.  
  406. # XXX Need a way to get menus as resources and bind them to callbacks
  407.  
  408. class Menu:
  409.     "One menu."
  410.     
  411.     def __init__(self, bar, title, after=0):
  412.         self.bar = bar
  413.         self.id, self.menu = self.bar.addmenu(title, after)
  414.         bar.menus[self.id] = self
  415.         self.items = []
  416.         
  417.     def delete(self):
  418.         self.bar.delmenu(self.id)
  419.         del self.bar.menus[self.id]
  420.         del self.bar
  421.         del self.items
  422.         del self.menu
  423.         del self.id
  424.     
  425.     def additem(self, label, shortcut=None, callback=None, kind=None):
  426.         self.menu.AppendMenu('x')        # add a dummy string
  427.         self.items.append(label, shortcut, callback, kind)
  428.         item = len(self.items)
  429.         self.menu.SetMenuItemText(item, label)        # set the actual text
  430.         if shortcut:
  431.             self.menu.SetItemCmd(item, ord(shortcut))
  432.         return item
  433.     
  434.     def addcheck(self, label, shortcut=None, callback=None):
  435.         return self.additem(label, shortcut, callback, 'check')
  436.     
  437.     def addradio(self, label, shortcut=None, callback=None):
  438.         return self.additem(label, shortcut, callback, 'radio')
  439.     
  440.     def addseparator(self):
  441.         self.menu.AppendMenu('(-')
  442.         self.items.append('', None, None, 'separator')
  443.     
  444.     def addsubmenu(self, label, title=''):
  445.         sub = Menu(self.bar, title, -1)
  446.         item = self.additem(label, '\x1B', None, 'submenu')
  447.         self.menu.SetItemMark(item, sub.id)
  448.         return sub
  449.     
  450.     def dispatch(self, id, item, window, event):
  451.         title, shortcut, callback, type = self.items[item-1]
  452.         if callback:
  453.             callback(id, item, window, event)
  454.  
  455.     def enable(self, onoff):
  456.         if onoff:
  457.             self.menu.EnableItem(0)
  458.         else:
  459.             self.menu.DisableItem(0)
  460.  
  461. class MenuItem:
  462.     def __init__(self, menu, title, shortcut=None, callback=None, kind=None):
  463.         self.item = menu.additem(title, shortcut, callback)
  464.         self.menu = menu
  465.         
  466.     def check(self, onoff):
  467.         self.menu.menu.CheckItem(self.item, onoff)
  468.  
  469.     def enable(self, onoff):
  470.         if onoff:
  471.             self.menu.menu.EnableItem(self.item)
  472.         else:
  473.             self.menu.menu.DisableItem(self.item)
  474.             
  475.     def settext(self, text):
  476.         self.menu.menu.SetMenuItemText(self.item, text)
  477.         
  478.     def setstyle(self, style):
  479.         self.menu.menu.SetItemStyle(self.item, style)
  480.         
  481.     def seticon(self, icon):
  482.         self.menu.menu.SetItemIcon(self.item, icon)
  483.         
  484.     def setcmd(self, cmd):
  485.         self.menu.menu.SetItemCmd(self.item, cmd)
  486.         
  487.     def setmark(self, cmd):
  488.         self.menu.menu.SetItemMark(self.item, cmd)
  489.         
  490.  
  491. class RadioItem(MenuItem):
  492.     def __init__(self, menu, title, shortcut=None, callback=None):
  493.         MenuItem.__init__(self, menu, title, shortcut, callback, 'radio')
  494.  
  495. class CheckItem(MenuItem):
  496.     def __init__(self, menu, title, shortcut=None, callback=None):
  497.         MenuItem.__init__(self, menu, title, shortcut, callback, 'check')
  498.  
  499. def Separator(menu):
  500.     menu.addseparator()
  501.  
  502. def SubMenu(menu, label, title=''):
  503.     return menu.addsubmenu(label, title)
  504.  
  505.  
  506. class AppleMenu(Menu):
  507.     
  508.     def __init__(self, bar, abouttext="About me...", aboutcallback=None):
  509.         Menu.__init__(self, bar, "\024")
  510.         self.additem(abouttext, None, aboutcallback)
  511.         self.addseparator()
  512.         self.menu.AppendResMenu('DRVR')
  513.     
  514.     def dispatch(self, id, item, window, event):
  515.         if item == 1:
  516.             Menu.dispatch(self, id, item, window, event)
  517.         else:
  518.             name = self.menu.GetMenuItemText(item)
  519.             OpenDeskAcc(name)
  520.  
  521. class Window:
  522.     """A single window belonging to an application"""
  523.     
  524.     def __init__(self, parent):
  525.         self.wid = None
  526.         self.parent = parent
  527.         
  528.     def open(self, bounds=(40, 40, 400, 400), resid=None):
  529.         if resid <> None:
  530.             self.wid = GetNewWindow(resid, -1)
  531.         else:
  532.             self.wid = NewWindow(bounds, self.__class__.__name__, 1,
  533.                 0, -1, 1, 0)
  534.         self.do_postopen()
  535.         
  536.     def do_postopen(self):
  537.         """Tell our parent we exist"""
  538.         self.parent.appendwindow(self.wid, self)
  539.         
  540.     def close(self):
  541.         self.do_postclose()
  542.             
  543.     def do_postclose(self):
  544.         self.parent.removewindow(self.wid)
  545.         self.parent = None
  546.         self.wid = None
  547.         
  548.     def SetPort(self):
  549.         # Convinience method
  550.         SetPort(self.wid)
  551.     
  552.     def do_inDrag(self, partcode, window, event):
  553.         where = event[3]
  554.         window.DragWindow(where, self.draglimit)
  555.     
  556.     draglimit = screenbounds
  557.     
  558.     def do_inGoAway(self, partcode, window, event):
  559.         where = event[3]
  560.         if window.TrackGoAway(where):
  561.             self.close()
  562.     
  563.     def do_inZoom(self, partcode, window, event):
  564.         (what, message, when, where, modifiers) = event
  565.         if window.TrackBox(where, partcode):
  566.             window.ZoomWindow(partcode, 1)
  567.     
  568.     def do_inZoomIn(self, partcode, window, event):
  569.         SetPort(window) # !!!
  570.         self.do_inZoom(partcode, window, event)
  571.     
  572.     def do_inZoomOut(self, partcode, window, event):
  573.         SetPort(window) # !!!
  574.         self.do_inZoom(partcode, window, event)
  575.     
  576.     def do_inGrow(self, partcode, window, event):
  577.         (what, message, when, where, modifiers) = event
  578.         result = window.GrowWindow(where, self.growlimit)
  579.         if result:
  580.             height = (result>>16) & 0xffff    # Hi word
  581.             width = result & 0xffff        # Lo word
  582.             self.do_resize(width, height, window)
  583.     
  584.     growlimit = screenbounds
  585.     
  586.     def do_resize(self, width, height, window):
  587.         window.SizeWindow(width, height, 0)
  588.         self.do_postresize(width, height, window)
  589.     
  590.     def do_postresize(self, width, height, window):
  591.         SetPort(window)
  592.         InvalRect(window.GetWindowPort().portRect)
  593.     
  594.     def do_inContent(self, partcode, window, event):
  595.         #
  596.         # If we're not frontmost, select ourselves and wait for
  597.         # the activate event.
  598.         #
  599.         if FrontWindow() <> window:
  600.             window.SelectWindow()
  601.             return
  602.         # We are. Handle the event.
  603.         (what, message, when, where, modifiers) = event
  604.         SetPort(window)
  605.         local = GlobalToLocal(where)
  606.         self.do_contentclick(local, modifiers, event)
  607.         
  608.     def do_contentclick(self, local, modifiers, event):
  609.         print 'Click in contents at %s, modifiers %s'%(local, modifiers)
  610.     
  611.     def do_rawupdate(self, window, event):
  612.         if DEBUG: print "raw update for", window
  613.         SetPort(window)
  614.         window.BeginUpdate()
  615.         self.do_update(window, event)
  616.         window.EndUpdate()
  617.     
  618.     def do_update(self, window, event):
  619.         EraseRgn(window.GetWindowPort().visRgn)
  620.         
  621.     def do_activate(self, activate, event):
  622.         if DEBUG: print 'Activate %d for %s'%(activate, self.wid)
  623.         
  624. class ControlsWindow(Window):
  625.  
  626.     def do_rawupdate(self, window, event):
  627.         if DEBUG: print "raw update for", window
  628.         SetPort(window)
  629.         window.BeginUpdate()
  630.         self.do_update(window, event)
  631.         DrawControls(window)
  632.         window.DrawGrowIcon()
  633.         window.EndUpdate()
  634.     
  635.     def do_controlhit(self, window, control, pcode, event):
  636.         if DEBUG: print "control hit in", window, "on", control, "; pcode =", pcode
  637.  
  638.     def do_inContent(self, partcode, window, event):
  639.         if FrontWindow() <> window:
  640.             window.SelectWindow()
  641.             return
  642.         (what, message, when, where, modifiers) = event
  643.         SetPort(window)  # XXXX Needed?
  644.         local = GlobalToLocal(where)
  645.         ctltype, control = FindControl(local, window)
  646.         if ctltype and control:
  647.             pcode = control.TrackControl(local)
  648.             if pcode:
  649.                 self.do_controlhit(window, control, pcode, event)
  650.         else:
  651.             if DEBUG: print "FindControl(%s, %s) -> (%s, %s)" % \
  652.                 (local, window, ctltype, control)
  653.             self.do_contentclick(local, modifiers, event)
  654.             
  655. class ScrolledWindow(ControlsWindow):
  656.     def __init__(self, parent):
  657.         self.barx = self.bary = None
  658.         self.barx_enabled = self.bary_enabled = 1
  659.         self.activated = 1
  660.         ControlsWindow.__init__(self, parent)
  661.  
  662.     def scrollbars(self, wantx=1, wanty=1):
  663.         SetPort(self.wid)
  664.         self.barx = self.bary = None
  665.         self.barx_enabled = self.bary_enabled = 1
  666.         x0, y0, x1, y1 = self.wid.GetWindowPort().portRect
  667.         vx, vy = self.getscrollbarvalues()
  668.         if vx == None: self.barx_enabled, vx = 0, 0
  669.         if vy == None: self.bary_enabled, vy = 0, 0
  670.         if wantx:
  671.             rect = x0-1, y1-(SCROLLBARWIDTH-1), x1-(SCROLLBARWIDTH-2), y1+1
  672.             self.barx = NewControl(self.wid, rect, "", 1, vx, 0, 32767, 16, 0)
  673.             if not self.barx_enabled: self.barx.HiliteControl(255)
  674. ##            InvalRect(rect)
  675.         if wanty:
  676.             rect = x1-(SCROLLBARWIDTH-1), y0-1, x1+1, y1-(SCROLLBARWIDTH-2)
  677.             self.bary = NewControl(self.wid, rect, "", 1, vy, 0, 32767, 16, 0)
  678.             if not self.bary_enabled: self.bary.HiliteControl(255)
  679. ##            InvalRect(rect)
  680.             
  681.     def do_postclose(self):
  682.         self.barx = self.bary = None
  683.         ControlsWindow.do_postclose(self)
  684.         
  685.     def do_activate(self, onoff, event):
  686.         self.activated = onoff
  687.         if onoff:
  688.             if self.barx and self.barx_enabled:
  689.                 self.barx.HiliteControl(0)
  690.             if self.bary and self.bary_enabled:
  691.                 self.bary.HiliteControl(0)
  692.         else:
  693.             if self.barx:
  694.                 self.barx.HiliteControl(255)
  695.             if self.bary:
  696.                 self.bary.HiliteControl(255)
  697.             
  698.     def do_postresize(self, width, height, window):
  699.         l, t, r, b = self.wid.GetWindowPort().portRect
  700.         if self.barx:
  701.             self.barx.MoveControl(l-1, b-(SCROLLBARWIDTH-1))
  702.             self.barx.SizeControl((r-l)-(SCROLLBARWIDTH-2), SCROLLBARWIDTH)
  703.         if self.bary:
  704.             self.bary.MoveControl(r-(SCROLLBARWIDTH-1), t-1)
  705.             self.bary.SizeControl(SCROLLBARWIDTH, (b-t)-(SCROLLBARWIDTH-2))
  706.         InvalRect((l, t, r, b))
  707.  
  708.     def do_controlhit(self, window, control, pcode, event):
  709.         if control == self.barx:
  710.             bar = self.barx
  711.             which = 'x'
  712.         elif control == self.bary:
  713.             bar = self.bary
  714.             which = 'y'
  715.         else:
  716.             return 0
  717.         value = None
  718.         if pcode == inUpButton:
  719.             what = '-'
  720.         elif pcode == inDownButton:
  721.             what = '+'
  722.         elif pcode == inPageUp:
  723.             what = '--'
  724.         elif pcode == inPageDown:
  725.             what = '++'
  726.         else:
  727.             what = 'set'
  728.             value = bar.GetControlValue()
  729.         self.scrollbar_callback(which, what, value)
  730.         self.updatescrollbars()
  731.         return 1
  732.         
  733.     def updatescrollbars(self):
  734.         SetPort(self.wid)
  735.         vx, vy = self.getscrollbarvalues()
  736.         if self.barx:
  737.             if vx == None:
  738.                 self.barx.HiliteControl(255)
  739.                 self.barx_enabled = 0
  740.             else:
  741.                 if not self.barx_enabled:
  742.                     self.barx_enabled = 1
  743.                     if self.activated:
  744.                         self.barx.HiliteControl(0)
  745.                 self.barx.SetControlValue(vx)
  746.         if self.bary:
  747.             if vy == None:
  748.                 self.bary.HiliteControl(255)
  749.                 self.bary_enabled = 0
  750.             else:
  751.                 if not self.bary_enabled:
  752.                     self.bary_enabled = 1
  753.                     if self.activated:
  754.                         self.bary.HiliteControl(0)
  755.                 self.bary.SetControlValue(vy)
  756.             
  757.     # Auxiliary function: convert standard text/image/etc coordinate
  758.     # to something palatable as getscrollbarvalues() return
  759.     def scalebarvalue(self, absmin, absmax, curmin, curmax):
  760.         if curmin <= absmin and curmax >= absmax:
  761.             return None
  762.         if curmin <= absmin:
  763.             return 0
  764.         if curmax >= absmax:
  765.             return 32767
  766.         perc = float(curmin-absmin)/float(absmax-absmin)
  767.         return int(perc*32767)
  768.             
  769.     # To be overridden:
  770.     
  771.     def getscrollbarvalues(self):
  772.         return 0, 0
  773.         
  774.     def scrollbar_callback(self, which, what, value):
  775.         print 'scroll', which, what, value
  776.     
  777. class DialogWindow(Window):
  778.     """A modeless dialog window"""
  779.     
  780.     def open(self, resid):
  781.         self.wid = GetNewDialog(resid, -1)
  782.         self.do_postopen()
  783.         
  784.     def close(self):
  785.         self.do_postclose()
  786.         
  787.     def do_itemhit(self, item, event):
  788.         print 'Dialog %s, item %d hit'%(self.wid, item)
  789.         
  790.     def do_rawupdate(self, window, event):
  791.         pass
  792.  
  793. def ostypecode(x):
  794.     "Convert a long int to the 4-character code it really is"
  795.     s = ''
  796.     for i in range(4):
  797.         x, c = divmod(x, 256)
  798.         s = chr(c) + s
  799.     return s
  800.  
  801.  
  802. class TestApp(Application):
  803.     
  804.     "This class is used by the test() function"
  805.     
  806.     def makeusermenus(self):
  807.         self.filemenu = m = Menu(self.menubar, "File")
  808.         self.saveitem = MenuItem(m, "Save", "S", self.save)
  809.         Separator(m)
  810.         self.optionsmenu = mm = SubMenu(m, "Options")
  811.         self.opt1 = CheckItem(mm, "Arguments")
  812.         self.opt2 = CheckItem(mm, "Being hit on the head lessons")
  813.         self.opt3 = CheckItem(mm, "Complaints")
  814.         Separator(m)
  815.         self.quititem = MenuItem(m, "Quit", "Q", self.quit)
  816.     
  817.     def save(self, *args):
  818.         print "Save"
  819.     
  820.     def quit(self, *args):
  821.         raise self
  822.  
  823.  
  824. def test():
  825.     "Test program"
  826.     app = TestApp()
  827.     app.mainloop()
  828.  
  829.  
  830. if __name__ == '__main__':
  831.     test()
  832.